package com.jl.applet;

import opencard.core.service.CardServiceException;
import opencard.core.terminal.CommandAPDU;
import opencard.core.terminal.ResponseAPDU;
import opencard.opt.applet.AppletID;
import opencard.opt.applet.AppletInfo;
import opencard.opt.service.CardServiceUnexpectedResponseException;

import com.jl.card.ICard;

public class ISOApplet implements IApplet {

	// A default class byte for a SELECT card command
	protected final static byte SELECT_CLASS = (byte) 0x00;

	// The instruction byte for a SELECT card command
	protected final static byte SELECT_INS = (byte) 0xA4;

	// P1 = 04 (Selection by DF name)
	protected final static byte SELECT_P1 = (byte) 0x04;

	// P2 = 00 (First occurence)
	protected final static byte SELECT_P2 = (byte) 0x00;

	// SW1 and SW2 Normal Processing
	protected final static short SW_OK = (short) 0x9000;

	// Warning and Errors Status
	protected final static byte SELECT_SW1_WARNING = (byte) 0x62;
	protected final static byte SELECT_SW1_ERROR = (byte) 0x6A;
	protected final static byte SELECT_SW2_INVALID = (byte) 0x83;
	protected final static byte SELECT_SW2_UNFORMAT = (byte) 0x84;
	protected final static byte SELECT_SW2_UNSUPPORTED = (byte) 0x81;
	protected final static byte SELECT_SW2_NOTFOUND = (byte) 0x82;
	protected final static byte SELECT_SW2_INCORRECTP1P2 = (byte) 0x86;
	protected final static byte SELECT_SW2_INCORRECTLC = (byte) 0x87;

	@Override
	public AppletInfo select(ICard card, AppletID appletID)
			throws CardServiceException {

		CommandAPDU selectCommand = null;
		ResponseAPDU selectResponse = null;
		AppletInfo result = null;
		// Create and send command
		selectCommand = new CommandAPDU(6 + appletID.getBytes().length);
		selectCommand.setLength(0);
		selectCommand.append(SELECT_CLASS); // CLA
		selectCommand.append(SELECT_INS); // INS
		selectCommand.append(SELECT_P1); // P1
		selectCommand.append(SELECT_P2); // P2
		selectCommand.append((byte) appletID.getBytes().length); // Length In
		selectCommand.append(appletID.getBytes()); // Input Data
		selectResponse = card.sendCommandAPDU(selectCommand);

		switch ((short) (selectResponse.sw() & 0xFFFF)) {
		case SW_OK:
			// Response is OK
			result = new AppletInfo();
			result.setAppletID(appletID);
			result.setData(selectResponse);
			break;
		default:
			// 1st) solution => Problem during selection: Throw an exception
			// Cons: we loose the ResponseAPDU object..!
			// throw new
			// CardServiceUnexpectedResponseException("Status Words are 0x" +
			// Integer.toHexString((short) (selectResponse.sw() & 0xFFFF)));
			// 2nd) solution => we provide a result object w/ an impossible
			// AID and the entire ResponseAPDU object. Caller can test
			// either the AID, or the ResponseAPDU SW code. This also
			// alows to parse more carefully the error codes in subclasses.
			//
			// result = new AppletInfo();
			// result.setAppletID(new AppletID("BAD".getBytes()));
			// result.setData(selectResponse);
			// break;
			throw new CardServiceUnexpectedResponseException(
					"Status Words are 0x"
							+ Integer.toHexString((short) (selectResponse.sw() & 0xFFFF)));
		}
		return result;
	}

}
